// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.eva.android.shortvideo;

import android.annotation.TargetApi;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.drawable.AnimationDrawable;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.eva.android.widget.BaseActivity;
import com.eva.android.widget.alert.AlertDialog;
import com.eva.epc.common.file.FileHelper;
import com.x52im.rbchat.Const;
import com.x52im.rbchat.R;
import com.x52im.rbchat.logic.qrcode.utils.StatusBarUtils;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * 短视频录制界面.
 *
 * @author liuzhongjun, Jack Jiang
 * @since 4.4
 */
public class ShortVideoRecordActivity extends BaseActivity {

    private static final String TAG = ShortVideoRecordActivity.class.getSimpleName();

    /** 录制的视频的保存目录(目录结尾带"反斜线"了哦) */
    private String saveDirFromIntent = null;

    //UI
    private ImageView mRecordControl;
    private SurfaceView surfaceView;
    private SurfaceHolder mSurfaceHolder;
    private Chronometer mRecordTime;
    private TextView mMaxTimeHint;
    // 录制动画（一闪一闪的小红点）
    private ImageView mRecordingAnim;
    // 关闭按钮
    private Button mCloseBtn;

    //DATA
    // 标记，判断当前是否正在录制
    private boolean isRecording = false;
    // 录制开始时的时间戳（用于录制完成时计算录制时间的）
    private long startRecordingTimestamp = 0;

    // 存储文件
    private Camera mCamera;
    private MediaRecorder mediaRecorder;
    private String currentVideoFilePath;

    private MediaRecorder.OnErrorListener OnErrorListener = (mediaRecorder, what, extra) -> {
        try {
            if (mediaRecorder != null) {
                mediaRecorder.reset();
            }
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
        }
    };

    private SurfaceHolder.Callback mSurfaceCallBack = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            initCamera();
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
            if (mSurfaceHolder.getSurface() == null) {
                return;
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            releaseCamera();
        }
    };

    /** 录制事件监听器 */
    private MediaRecorder.OnInfoListener mMediaRecorderOnInfoListener = (mediaRecorder, what, extra) -> {
        // 到达了最大录制时长
        if(what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
            Log.v(TAG, "【视频录制】到达了最大录制时长（"+ Const.SHORT_VIDEO_RECORD_MAX_TIME+"ms）");
            // 完成录制
            completeRecording(true, Const.SHORT_VIDEO_RECORD_MAX_TIME);
        }
    };

    @Override
    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 视频保存目录
        this.saveDirFromIntent = getIntent().getStringExtra("__saveDir__");
        // 养成良好习惯：首先设置主layout，确保后绪的操作中使用到的组件都可以被find到
        setContentView(R.layout.common_short_video_record_activity);
        // 对界面上方进行全面屏设置
        StatusBarUtils.immersiveStatusBar(this, findViewById(R.id.toolbar),0.0f);

        // 确保视频保存目录参数是有效的
        if(this.saveDirFromIntent == null) {
            new AlertDialog.Builder(this)
                    .setTitle(this.getResources().getString(R.string.general_prompt))
                    .setMessage(this.getResources().getString(R.string.short_video_dir_not_prepared))
                    .setPositiveButton(this.getResources().getString(R.string.general_ok), (dialog, which) -> ShortVideoRecordActivity.super.finish())
                    .show();
        }

        initView();
        initListeners();
    }

    private void initView() {
        surfaceView = findViewById(R.id.common_short_video_record_ac_record_surfaceView);
        mRecordControl = findViewById(R.id.common_short_video_record_ac_record_control);
        mRecordTime = findViewById(R.id.common_short_video_record_ac_record_time);
        mMaxTimeHint = findViewById(R.id.common_short_video_record_ac_record_maxtime);
        mRecordingAnim = findViewById(R.id.common_short_video_record_ac_record_anim);
        mCloseBtn = findViewById(R.id.common_short_video_record_ac_record_closeBtn);

        mMaxTimeHint.setText("(最长"+(Const.SHORT_VIDEO_RECORD_MAX_TIME/1000)+"秒)");

        // 配置SurfaceHolder
        mSurfaceHolder = surfaceView.getHolder();
        // 设置Surface不需要维护自己的缓冲区
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // 设置分辨率
        mSurfaceHolder.setFixedSize(320, 280);
        // 设置该组件不会让屏幕自动关闭
        mSurfaceHolder.setKeepScreenOn(true);
        // 回调接口
        mSurfaceHolder.addCallback(mSurfaceCallBack);
    }

    private void initListeners() {
        // 录制控制按钮点击事件
        mRecordControl.setOnClickListener(view -> {
            switch (view.getId()) {
                case R.id.common_short_video_record_ac_record_control: {
                    if (!isRecording) {
                        startRecording();
                    } else {
                        completeRecording(false, -1);
                        break;
                    }
                }
            }
        });

        // 关闭的点击事件
        mCloseBtn.setOnClickListener(view -> finish());
    }

    /**
     * 初始化摄像头
     *
     * @throws IOException
     * @author liuzhongjun
     */
    private void initCamera() {

        try {
            if (mCamera != null) {
                releaseCamera();
            }

            mCamera = Camera.open();
            if (mCamera == null) {
                Toast.makeText(this, "未能获取到相机！", Toast.LENGTH_SHORT).show();
                return;
            }

            //将相机与SurfaceHolder绑定
            mCamera.setPreviewDisplay(mSurfaceHolder);
            //配置CameraParams
            configCameraParams();
            //启动相机预览
            mCamera.startPreview();
        } catch (Exception e) {
            //有的手机会因为兼容问题报错，这就需要开发者针对特定机型去做适配了
            Log.w(TAG, "【视频录制】Error initCamera: " + e.getMessage(), e);
        }
    }

    /**
     * 设置摄像头为竖屏
     *
     * @author lip
     * @date 2015-3-16
     */
    private void configCameraParams() {
        Camera.Parameters params = mCamera.getParameters();
        //设置相机的横竖屏(竖屏需要旋转90°)
        if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
            params.set("orientation", "portrait");
            mCamera.setDisplayOrientation(90);
        } else {
            params.set("orientation", "landscape");
            mCamera.setDisplayOrientation(0);
        }

        //设置对焦模式
//      params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        List<String> focusModes = params.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        }

        // 以下方法只在android level 14及以上版本才有的，代码里要加判断哦！！！
        // http://www.android-doc.com/reference/android/hardware/Camera.Parameters.html#setRecordingHint(boolean)
        if(Build.VERSION.SDK_INT >= 14) {
            //缩短Recording启动时间
            params.setRecordingHint(true);
            //影像稳定能力
            configVideoStabilization(params);
        }

        mCamera.setParameters(params);
    }

    @TargetApi(15)
    private void configVideoStabilization(Camera.Parameters params) {
        //影像稳定能力
        if (params.isVideoStabilizationSupported())
            params.setVideoStabilization(true);
    }

    /**
     * 配置MediaRecorder()
     */
    private void configMediaRecorder() {
        mediaRecorder = new MediaRecorder();
        mediaRecorder.reset();
        mediaRecorder.setCamera(mCamera);
        mediaRecorder.setOnErrorListener(OnErrorListener);

        mediaRecorder.setOnInfoListener(this.mMediaRecorderOnInfoListener);
        // 设置最大录制时长
        mediaRecorder.setMaxDuration(Const.SHORT_VIDEO_RECORD_MAX_TIME);

        //使用SurfaceView预览
        mediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        //1.设置采集声音
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //设置采集图像
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        //2.设置视频，音频的输出格式 mp4
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
        //3.设置音频的编码格式
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        //设置图像的编码格式
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        //设置立体声
//      mediaRecorder.setAudioChannels(2);
        //设置最大录制的大小 单位，字节
//      mediaRecorder.setMaxFileSize(1024 * 1024);

        //视录制录制质量（当前默认录制480P的视频，当前的各项参数可以确保录制出的视频跟微信的画质、文件大小等持平）
        CamcorderProfile mProfile = null;
        try{
            mProfile= CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
        } catch(Exception e) {
            Log.w(TAG, "【视频录制】此手机不支持QUALITY_480P录制，为保兼容性将使用最低质量进行录制。", e);
            mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
        }

        Log.i(TAG, "【视频录制】预定义录制参数中，mProfile.videoFrameWidth="
                +mProfile.videoFrameWidth+", mProfile.videoFrameHeight="+mProfile.videoFrameHeight);

        mediaRecorder.setAudioEncodingBitRate(44100);
        if (mProfile.videoBitRate > 2 * 1024 * 1024)
            mediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);
        else
            mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
        mediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);

        //设置选择角度，顺时针方向，因为默认是逆向90度的，这样图像就是正常显示了,这里设置的是观看保存后的视频的角度
        mediaRecorder.setOrientationHint(90);
        //设置录像的分辨率
        mediaRecorder.setVideoSize(mProfile.videoFrameWidth,mProfile.videoFrameHeight);//352, 288);

        //设置录像视频输出地址
        mediaRecorder.setOutputFile(currentVideoFilePath);
    }

    /**
     * 释放摄像头资源
     *
     * @author liuzhongjun
     * @date 2016-2-5
     */
    private void releaseCamera() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 开始录制视频
     */
    private boolean startRecord() {

        try {
            // 开始录制时不需要再调用一次这个方法了，因为本界面显示时在surfaceview初始化完成它就被调用
            // 过了，再次调用的话，一是没有必要，二是这会导致更多的耗时和界面的瞬间闪烁，影响用户体验
//          initCamera();

            //录制视频前必须先解锁Camera
            mCamera.unlock();
            configMediaRecorder();

            //开始录制
            mediaRecorder.prepare();
            mediaRecorder.start();
        } catch (Exception e) {
            Log.w(TAG, e);
            return false;
        }
        return true;
    }

    /**
     * 停止录制视频
     */
    private void stopRecord() {
        // 设置后不会崩
        mediaRecorder.setOnErrorListener(null);
        mediaRecorder.setPreviewDisplay(null);
        //停止录制
        mediaRecorder.stop();
        mediaRecorder.reset();
        //释放资源
        mediaRecorder.release();
        mediaRecorder = null;
    }

    /**
     * 点击中间按钮，执行的UI更新操作
     */
    private void refreshControlUI() {
        if (this.isRecording) {
            //录像时间计时
            mRecordTime.setBase(SystemClock.elapsedRealtime());
            mRecordTime.start();

            // 设置按钮此状态下的图标
            mRecordControl.setImageResource(R.drawable.common_short_video_recordvideo_stop);
            //1s后才能按停止录制按钮
            mRecordControl.setEnabled(false);

            // 显示录制动画
            mRecordingAnim.setImageResource(R.drawable.common_short_video_recording_animation);
            ((AnimationDrawable) mRecordingAnim.getDrawable()).start();

            new Handler().postDelayed(() -> mRecordControl.setEnabled(true), 1000);
        } else {
            mRecordTime.stop();
            mRecordControl.setImageResource(R.drawable.common_short_video_recordvideo_start);
            mRecordingAnim.setImageResource(R.drawable.common_short_video_recordvideo_start_amination_normal);
        }
    }

    /**
     * 录制开始
     */
    public void startRecording() {
        // 视频文件保存路径，configMediaRecorder方法中会设置
        currentVideoFilePath = this.saveDirFromIntent + getTempVideoName();

        // 如果目录不存在就创建之
        File dir = new File(this.saveDirFromIntent);
        if(!dir.exists())
            dir.mkdirs();

        //开始录制视频
        if (!startRecord()) {
            new AlertDialog.Builder(this)
                    .setTitle(this.getResources().getString(R.string.general_prompt))
                    .setMessage("视频录制启动时出错了，请稍后再试！")
                    .setPositiveButton(this.getResources().getString(R.string.general_ok), (dialog, which) -> ShortVideoRecordActivity.super.finish())
                    .show();
            return;
        }

        this.isRecording = true;
        // 开始录制时间
        this.startRecordingTimestamp = System.currentTimeMillis();

        refreshControlUI();
    }

    /**
     * 录制完成。
     */
    public void completeRecording(boolean reachedMaxRecordTime, long _recordDuration) {
//        //停止视频录制
//        stopRecord();
//
//        // 本次录制的时长
//        long recordDuration = (_recordDuration == -1?System.currentTimeMillis() - this.startRecordingTimestamp : _recordDuration);
//        // 重置
//        this.startRecordingTimestamp = 0;
//
//        //先给Camera加锁后再释放相机
//        mCamera.lock();
//        releaseCamera();
//
//        this.isRecording = false;
//
//        refreshControlUI();

        // 本次录制的时长
        long recordDuration = (_recordDuration == -1?System.currentTimeMillis() - this.startRecordingTimestamp : _recordDuration);

        // 先取消录制
        this.cancelRecordingNoConfirm(false);

        Log.i(TAG, "【视频录制】视频录制完成(时长:"+recordDuration+"ms)，保存路径是：" + this.currentVideoFilePath);

        // 再调置回调数据
        Intent intent = new Intent();
        intent.putExtra("path", this.currentVideoFilePath);
        intent.putExtra("duration", recordDuration);
        intent.putExtra("reachedMaxRecordTime", reachedMaxRecordTime);
        setResult(RESULT_OK, intent);

        super.finish();
    }

    /**
     * 取消录制。
     */
    public void cancelRecordingNoConfirm(boolean deleteFile) {
        if(this.isRecording) {
            Log.d(TAG, "【视频录制】当前正在录制中，cancelRecording时需先停止录制相关逻辑。。。");

            try{
                //停止视频录制
                stopRecord();

                // 重置
                this.startRecordingTimestamp = 0;

                //先给Camera加锁后再释放相机
                mCamera.lock();
                releaseCamera();

                this.isRecording = false;

                refreshControlUI();

                // 如果需要删除录制完成的文件
                if(deleteFile && this.currentVideoFilePath != null)
                {
                    FileHelper.deleteFile(this.currentVideoFilePath);
                }
            } catch (Exception e) {
                Log.w(TAG, "【视频录制】cancelRecording时发生异常，原因："+e.getMessage(), e);
            }
        } else {
            Log.d(TAG, "【视频录制】当前未在录制中，cancelRecording时直接通出当前界面即可。");
        }
    }

    /**
     * 重写finish方法，实现时关闭界面时能进行相应的提示和处理。
     */
    @Override
    public void finish() {
        if(this.isRecording) {
            new AlertDialog.Builder(this)
                    .setTitle(this.getResources().getString(R.string.general_prompt))
                    .setMessage("视频正在录制中，点击\"确认\"将取消本次录制并退出当前界面。")
                    .setPositiveButton(this.getResources().getString(R.string.general_ok), (dialog, which) -> {
                        cancelRecordingNoConfirm(true);
                        ShortVideoRecordActivity.super.finish();
                    })
                    .setNegativeButton(this.getResources().getString(R.string.general_cancel), null)
                    .show();
        }
        else
            super.finish();
    }

    private String getTempVideoName() {
        return "shortvideo_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".mp4";
    }
}
